package com.biglead.demo.service.impl;

import com.biglead.demo.common.R;
import com.biglead.demo.config.SnowFlakeCompone;
import com.biglead.demo.pojo.SecKillMessage;
import com.biglead.demo.pojo.SeckillGoods;
import com.biglead.demo.pojo.SeckillOrder;
import com.biglead.demo.rabbit.order.common.OrderMQSender;
import com.biglead.demo.service.SecKillGoodsService;
import com.biglead.demo.service.SecKillOrderService;
import com.biglead.demo.service.SecKillService;
import com.biglead.demo.utils.JsonUtils;
import com.biglead.demo.utils.MD5Utils;
import com.biglead.demo.utils.UUIDUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户分类表 服务实现类
 * </p>
 *
 * @author 早起的年轻人
 * @since 2023-03-14
 */
@Service("secKillService")
@Slf4j
public class SecKillServiceImpl implements SecKillService, InitializingBean {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SecKillGoodsService secKillGoodsService;

    @Autowired
    private SecKillOrderService secKillOrderService;

    @Autowired
    private OrderMQSender mqSender;
    // 空库存的 map 集合
    private Map<Long, Boolean> emptyStockMap = new HashMap<>();
    @Autowired
    SnowFlakeCompone snowFlakeCompone;
    @Override
    public R isToSecKill(Long goodsId, Long userId) {

        // 重复抢购
        SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.opsForValue().get("order:" + userId + ":" + goodsId);
        if (!Objects.isNull(seckillOrder)) {
            return R.error("重复抢购");
        }
        // 内存标记，减少 Redis 的访问
        if (emptyStockMap.get(goodsId)) {
            // 库存为空
            return R.error("商品库存不足");
        }
        //库存 key
        String redisStockKey = "seckillGoods:" + goodsId;

        Boolean aBoolean = redisTemplate.hasKey(redisStockKey);
        if(Boolean.FALSE.equals(aBoolean)){
            emptyStockMap.put(goodsId, true);
            return R.error("商品库存不足");
        }

        ValueOperations valueOperations = redisTemplate.opsForValue();

        // 预减库存
        Long stock = valueOperations.decrement(redisStockKey);
        // 库存不足
        if (stock < 0) {
            emptyStockMap.put(goodsId, true);
            valueOperations.increment(redisStockKey);
            return R.error("商品库存不足");
        }
        //生成订单号
        long sn = snowFlakeCompone.getInstance().nextId();
        //保存到redis中 状态 doing 正在处理中
        redisTemplate.opsForValue().set("sn:"+sn, "doing");
        // 秒杀消息
        SecKillMessage message = new SecKillMessage(userId, goodsId,sn);
        mqSender.sendSecKillMessage(JsonUtils.toJson(message));
        //把订单号返回给前端
        return R.okData(sn);
    }


    /**
     * 初始化秒杀商品数量到 redis 中
     *
     * @return
     */
    @Override
    public R startSeckillInit() {
        List<SeckillGoods> goods = secKillGoodsService.findAllSecKillGoods();
        if (CollectionUtils.isEmpty(goods)) {
            return R.error("无秒杀商品");
        }

        goods.forEach(g -> {
            log.info("初始化秒杀商品 goodsId:{} stock: {}", g.getGoodsId(), g.getStockCount());
            redisTemplate.opsForValue().set("seckillGoods:" + g.getGoodsId(), g.getStockCount());
            emptyStockMap.put(g.getGoodsId(), false);
        });
        return R.ok("初始化完成");
    }

    @Override
    public R getResult(Long goodsId, Long userId) {

        SeckillOrder secKillOrder = secKillOrderService.findSecKillOrder(goodsId, userId);
        if (!Objects.isNull(secKillOrder)) {
            return R.okData(secKillOrder.getOrderId());
        }
        if (redisTemplate.hasKey("isStockEmpty:" + goodsId)) {
            // 下单失败，库存不足
            return R.error("下单失败 库存不足");
        }
        // 排队中
        return R.error("排队中");


    }

    @Override
    public R createPath(Long userId, Long goodsId) {
        String path = MD5Utils.md5(UUIDUtils.uuid() + "123456");
        redisTemplate.opsForValue().set("seckillPath:" + userId + ":" + goodsId, path, 60, TimeUnit.SECONDS);
        return R.ok(path);
    }

    @Override
    public boolean checkPath(String path, Long userId, Long goodsId) {

        String redisPath = (String) redisTemplate.opsForValue().get("seckillPath:" + userId + ":" + goodsId);

        return path.equals(redisPath);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.startSeckillInit();
    }
}
